source('../settings/settings.R')
source('commonFunctions.R')
library(nlme)
set.seed(43)
drive1 <- read.csv('../data/processed/analysis/TT1_Drive_1_PP.csv')
drive2 <- read.csv('../data/processed/Analysis/TT1_Drive_2_PP.csv')
drive3 <- read.csv('../data/processed/Analysis/TT1_Drive_3_PP.csv')
drive4 <- read.csv('../data/processed/Analysis/TT1_Drive_4_PP.csv', stringsAsFactors = T)
dfSeg <- data.frame(rep(1, nrow(drive4)), rep(2, nrow(drive4)), rep(3, nrow(drive4)), rep(4, nrow(drive4)))
names(dfSeg) <- c("Seg1", "Seg2", "Seg3", "Seg4")
combinedDf_Seg1 <- cbind(drive4,
drive1$MeanPP_Seg0,
drive2$MeanPP_Seg1, drive3$MeanPP_Seg1,
drive2$MeanPP_Seg0_1, drive3$MeanPP_Seg0_1,
drive2$StdPP_Seg1, drive3$StdPP_Seg1,
drive2$StdPP_Seg0_1, drive3$StdPP_Seg0_1,
drive2$MeanPP_AccHigh1, drive3$MeanPP_AccHigh1,
drive2$X.MeanPP_AccLow1, drive3$X.MeanPP_AccLow1,
drive2$StdPP_AccHigh1, drive3$StdPP_AccHigh1,
drive2$StdPP_AccLow1, drive3$StdPP_AccLow1,
dfSeg$Seg1
)
combinedDf_Seg2 <- cbind(drive4,
drive1$MeanPP_Seg0,
drive2$MeanPP_Seg2, drive3$MeanPP_Seg2,
drive2$MeanPP_Seg0_2, drive3$MeanPP_Seg0_2,
drive2$StdPP_Seg2, drive3$StdPP_Seg2,
drive2$StdPP_Seg0_2, drive3$StdPP_Seg0_2,
drive2$MeanPP_AccHigh2, drive3$MeanPP_AccHigh2,
drive2$X.MeanPP_AccLow2, drive3$X.MeanPP_AccLow2,
drive2$StdPP_AccHigh2, drive3$StdPP_AccHigh2,
drive2$StdPP_AccLow2, drive3$StdPP_AccLow2,
dfSeg$Seg2
)
combinedDf_Seg3 <- cbind(drive4,
drive1$MeanPP_Seg0,
drive2$MeanPP_Seg3, drive3$MeanPP_Seg3,
drive2$MeanPP_Seg0_3, drive3$MeanPP_Seg0_3,
drive2$StdPP_Seg3, drive3$StdPP_Seg3,
drive2$StdPP_Seg0_3, drive3$StdPP_Seg0_3,
drive2$MeanPP_AccHigh3, drive3$MeanPP_AccHigh3,
drive2$X.MeanPP_AccLow3, drive3$X.MeanPP_AccLow3,
drive2$StdPP_AccHigh3, drive3$StdPP_AccHigh3,
drive2$StdPP_AccLow3, drive3$StdPP_AccLow3,
dfSeg$Seg3
)
combinedDf_Seg4 <- cbind(drive4,
drive1$MeanPP_Seg0,
drive2$MeanPP_Seg4, drive3$MeanPP_Seg4,
drive2$MeanPP_Seg0_4, drive3$MeanPP_Seg0_4,
drive2$StdPP_Seg4, drive3$StdPP_Seg4,
drive2$StdPP_Seg0_4, drive3$StdPP_Seg0_4,
drive2$MeanPP_AccHigh4, drive3$MeanPP_AccHigh4,
drive2$X.MeanPP_AccLow4, drive3$X.MeanPP_AccLow4,
drive2$StdPP_AccHigh4, drive3$StdPP_AccHigh4,
drive2$StdPP_AccLow4, drive3$StdPP_AccLow4,
dfSeg$Seg4
)
common_names <- c("PP_Dev_1_Turning",
"PP_Dev_2_Straight", "PP_Dev_3_Straight",
"PP_Dev_2_Turning", "PP_Dev_3_Turning",
"Std_PP_2_Straight", "Std_PP_3_Straight",
"Std_PP_2_Turning", "Std_PP_3_Turning",
"Mean_PP_2_AccHigh", "Mean_PP_3_AccHigh",
"Mean_PP_2_AccLow", "Mean_PP_3_AccLow",
"Std_PP_2_AccHigh", "Std_PP_3_AccHigh",
"Std_PP_2_AccLow", "Std_PP_3_AccLow",
"Segment")
names(combinedDf_Seg1) <- c(names(drive4), common_names)
names(combinedDf_Seg2) <- c(names(drive4), common_names)
names(combinedDf_Seg3) <- c(names(drive4), common_names)
names(combinedDf_Seg4) <- c(names(drive4), common_names)
# combinedDf_Seg1$Subject <- paste0(as.factor(combinedDf_Seg1$Subject), ".S1")
# combinedDf_Seg2$Subject <- paste0(as.factor(combinedDf_Seg2$Subject), ".S2")
# combinedDf_Seg3$Subject <- paste0(as.factor(combinedDf_Seg3$Subject), ".S3")
# combinedDf_Seg4$Subject <- paste0(as.factor(combinedDf_Seg4$Subject), ".S4")
combinedDf <- rbind(combinedDf_Seg1, combinedDf_Seg2, combinedDf_Seg3, combinedDf_Seg4)
# combinedDf$Subject <- paste0("#", str_pad(combinedDf$Subject, 2, pad="0"))
combinedDf$Segment <- as.factor(combinedDf$Segment)
combinedDf$ActivityEncoded <- factor(ifelse(combinedDf$Activity == "NO", "1", ifelse(combinedDf$Activity == "C", "2", "3")))
combinedDf <- combinedDf[complete.cases(combinedDf),]
combinedDf$Subject = as.factor(combinedDf$Subject)
model = lm(PP_After ~
PP_Dev_2_Straight +
PP_Dev_3_Straight +
PP_Dev_2_Turning +
PP_Dev_3_Turning +
Std_PP_2_Straight +
Std_PP_3_Straight +
Std_PP_2_Turning +
Std_PP_3_Turning +
# PP_Prior +
factor(ActivityEncoded),
data=combinedDf, random = ~1|factor(Subject), method = "REML")
method = 'REML' is not supported. Using 'qr'In lm.fit(x, y, offset = offset, singular.ok = singular.ok, ...) :
extra argument ‘random’ will be disregarded
# anova(model)
summary(model)
Call:
lm(formula = PP_After ~ PP_Dev_2_Straight + PP_Dev_3_Straight +
PP_Dev_2_Turning + PP_Dev_3_Turning + Std_PP_2_Straight +
Std_PP_3_Straight + Std_PP_2_Turning + Std_PP_3_Turning +
factor(ActivityEncoded), data = combinedDf, method = "REML",
random = ~1 | factor(Subject))
Residuals:
Min 1Q Median 3Q Max
-0.17764 -0.07137 0.00092 0.05144 0.34502
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.02294 0.04870 -0.471 0.6393
PP_Dev_2_Straight 0.68712 0.15583 4.410 4.45e-05 ***
PP_Dev_3_Straight -0.37734 0.23618 -1.598 0.1155
PP_Dev_2_Turning -0.22015 0.14683 -1.499 0.1391
PP_Dev_3_Turning 0.38632 0.22101 1.748 0.0857 .
Std_PP_2_Straight 0.02144 0.38757 0.055 0.9561
Std_PP_3_Straight 0.50369 0.36818 1.368 0.1765
Std_PP_2_Turning -0.08343 0.50205 -0.166 0.8686
Std_PP_3_Turning -0.95800 0.60836 -1.575 0.1207
factor(ActivityEncoded)2 0.08647 0.03285 2.633 0.0108 *
factor(ActivityEncoded)3 0.17032 0.03184 5.349 1.51e-06 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.0993 on 59 degrees of freedom
Multiple R-squared: 0.5613, Adjusted R-squared: 0.4869
F-statistic: 7.548 on 10 and 59 DF, p-value: 1.338e-07
plot(model)




No Random Effects
linearModel1 <- lm(PP_After ~
Mean_PP_2_AccHigh
+ Mean_PP_2_AccLow
+ Mean_PP_3_AccHigh
+ Mean_PP_3_AccLow
+ Std_PP_2_AccHigh
+ Std_PP_2_AccLow
+ Std_PP_3_AccHigh
+ Std_PP_3_AccLow
# + PP_Prior
+ factor(ActivityEncoded),
data=combinedDf)
# anova(model)
summary(linearModel1)
Call:
lm(formula = PP_After ~ Mean_PP_2_AccHigh + Mean_PP_2_AccLow +
Mean_PP_3_AccHigh + Mean_PP_3_AccLow + Std_PP_2_AccHigh +
Std_PP_2_AccLow + Std_PP_3_AccHigh + Std_PP_3_AccLow + factor(ActivityEncoded),
data = combinedDf)
Residuals:
Min 1Q Median 3Q Max
-0.143483 -0.066038 -0.007552 0.051595 0.300313
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.06552 0.03640 -1.800 0.07695 .
Mean_PP_2_AccHigh 1.63376 0.50590 3.229 0.00203 **
Mean_PP_2_AccLow -1.15253 0.49763 -2.316 0.02405 *
Mean_PP_3_AccHigh 0.74436 0.31520 2.362 0.02152 *
Mean_PP_3_AccLow -0.66142 0.33913 -1.950 0.05589 .
Std_PP_2_AccHigh -1.28974 1.45755 -0.885 0.37982
Std_PP_2_AccLow 0.79583 1.15728 0.688 0.49435
Std_PP_3_AccHigh 0.15278 0.94374 0.162 0.87195
Std_PP_3_AccLow 0.91693 0.83810 1.094 0.27838
factor(ActivityEncoded)2 0.08724 0.03041 2.869 0.00571 **
factor(ActivityEncoded)3 0.14810 0.03043 4.867 8.83e-06 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.09353 on 59 degrees of freedom
Multiple R-squared: 0.6108, Adjusted R-squared: 0.5448
F-statistic: 9.259 on 10 and 59 DF, p-value: 5.37e-09
plot(linearModel1)




With Random Effects
linearModel1 <- lme(PP_After ~
Mean_PP_2_AccHigh
+ Mean_PP_2_AccLow
+ Mean_PP_3_AccHigh
+ Mean_PP_3_AccLow
+ Std_PP_2_AccHigh
+ Std_PP_2_AccLow
+ Std_PP_3_AccHigh
+ Std_PP_3_AccLow
# + PP_Prior
+ factor(ActivityEncoded),
data=combinedDf, random = ~1|factor(Subject), method = "REML")
# anova(model)
summary(linearModel1)
Linear mixed-effects model fit by REML
Data: combinedDf
Random effects:
Formula: ~1 | factor(Subject)
(Intercept) Residual
StdDev: 0.1403901 2.578859e-17
Fixed effects: PP_After ~ Mean_PP_2_AccHigh + Mean_PP_2_AccLow + Mean_PP_3_AccHigh + Mean_PP_3_AccLow + Std_PP_2_AccHigh + Std_PP_2_AccLow + Std_PP_3_AccHigh + Std_PP_3_AccLow + factor(ActivityEncoded)
Correlation:
(Intr) M_PP_2_AH M_PP_2_AL M_PP_3_AH M_PP_3_AL S_PP_2_AH S_PP_2_AL S_PP_3_AH S_PP_3_AL f(AE)2
Mean_PP_2_AccHigh -0.205
Mean_PP_2_AccLow 0.195 -0.962
Mean_PP_3_AccHigh -0.010 0.006 -0.030
Mean_PP_3_AccLow 0.091 -0.071 0.032 -0.695
Std_PP_2_AccHigh 0.003 0.147 -0.187 0.084 -0.072
Std_PP_2_AccLow -0.072 0.041 -0.023 -0.130 0.082 -0.873
Std_PP_3_AccHigh -0.049 0.073 -0.122 -0.450 0.305 -0.337 0.191
Std_PP_3_AccLow 0.039 0.193 -0.209 0.378 -0.322 0.303 -0.240 -0.525
factor(ActivityEncoded)2 -0.657 0.084 -0.072 0.017 -0.063 -0.060 0.081 0.022 -0.033
factor(ActivityEncoded)3 -0.654 0.138 -0.127 0.052 -0.071 -0.027 0.027 0.052 0.028 0.433
Standardized Within-Group Residuals:
Min Q1 Med Q3 Max
-2.1525473 -0.3531523 0.0000000 0.5381368 6.4576419
Number of Observations: 70
Number of Groups: 21
plot(linearModel1)

Machine Learning
ppAfter <- combinedDf$PP_After
ppAfterArray <- matrix(ppAfter, nrow = 1,ncol = length(ppAfter))
thresholdPPAfter <- otsu(ppAfterArray, range=c(min(ppAfter), max(ppAfter))) # Expected Threshold > 0.10123
print(paste0('Threshold: ', thresholdPPAfter))
[1] "Threshold: 0.101235546875"
selectedDf <- combinedDf %>% select(
"Subject", "Activity", "PP_After", "PP_Prior",
"Mean_PP_2_AccHigh", "Mean_PP_3_AccHigh",
"Mean_PP_2_AccLow", "Mean_PP_3_AccLow",
"Std_PP_2_AccHigh", "Std_PP_3_AccHigh",
"Std_PP_2_AccLow", "Std_PP_3_AccLow")
selectedDf$Subject <- NULL
selectedDf$Activity_NO <- ifelse(selectedDf$Activity == "NO", 1, 0)
selectedDf$Activity_C <- ifelse(selectedDf$Activity == "C", 1, 0)
selectedDf$Activity_M <- ifelse(selectedDf$Activity == "M", 1, 0)
selectedDf$Activity <- NULL
# selectedDf$PP_Dev_1_Turning <- NULL
# selectedDf$Std_PP_2_Straight <- NULL
# selectedDf$Std_PP_2_Turning <- NULL
# selectedDf$Std_PP_3_Straight <- NULL
# selectedDf$Std_PP_3_Turning <- NULL
#
# # According to Linear model
# selectedDf$PP_Dev_2_Straight <- abs(selectedDf$PP_Dev_2_Straight)
# selectedDf$PP_Dev_3_Straight <- abs(selectedDf$PP_Dev_3_Straight)
# selectedDf$PP_Dev_2_Turning <- abs(selectedDf$PP_Dev_2_Turning)
# selectedDf$PP_Dev_3_Turning <- abs(selectedDf$PP_Dev_3_Turning)
# selectedDf$PP_Prior <- abs(selectedDf$PP_Prior) # NULL
selectedDf$Class <- ifelse(selectedDf$PP_After >= thresholdPPAfter, T, F)
selectedDf$PP_After <- NULL
print(names(selectedDf))
[1] "PP_Prior" "Mean_PP_2_AccHigh" "Mean_PP_3_AccHigh" "Mean_PP_2_AccLow" "Mean_PP_3_AccLow" "Std_PP_2_AccHigh"
[7] "Std_PP_3_AccHigh" "Std_PP_2_AccLow" "Std_PP_3_AccLow" "Activity_NO" "Activity_C" "Activity_M"
[13] "Class"
# library(mefa)
# combinedDf <- rep(combinedDf, 10)
set.seed(39)
n_folds <- 5
params <- param <- list(objective = "binary:logistic",
booster = "gbtree",
eval_metric = "auc",
eta = 0.1,
max_depth = 10,
alpha = 1,
lambda = 0,
gamma = 0.45,
min_child_weight = 0.3,
subsample = 0.5,
colsample_bytree = 1)
# XGBoost Model
xgb_m <- xgb.cv( params = param,
data = as.matrix(selectedDf %>% select(-Class)) ,
label = selectedDf$Class,
nrounds = 100,
verbose = F,
prediction = T,
maximize = F, # Change this value to F will help to run with more itineration
nfold = n_folds,
metrics = c("auc", "error"),
early_stopping_rounds = 50,
stratified = T,
scale_pos_weight = 2)
# xgb_m$evaluation_log[xgb_m$best_iteration,"test_auc_mean"]
xgb_m$evaluation_log[xgb_m$best_iteration,]
NA
Performance Metrics
# Prediction
selectedDf$clsPred <- round(xgb_m$pred)
computePerformanceResults <- function(sdat){
sdat = sdat[complete.cases(sdat),]
acc = sum(sdat[,1] == sdat[,2])/nrow(sdat)
conf_mat = table(sdat)
specif = conf_mat[1,1]/sum(conf_mat[,1])
sensiv = conf_mat[2,2]/sum(conf_mat[,2])
preci = conf_mat[2,2]/sum(conf_mat[2,])
npv = conf_mat[1,1]/sum(conf_mat[1,])
return(c(acc,specif,sensiv,preci,npv))
}
# Get average performance
performance <- computePerformanceResults(selectedDf %>% select(Class, clsPred))
acc <- performance[1]
prec <- performance[4]
recall <- performance[3]
spec <- performance[2]
npv <- performance[5]
f1 <- (2 * recall * prec) / (recall + prec)
auc <- as.numeric(xgb_m$evaluation_log[xgb_m$best_iteration, "test_auc_mean"])
print(paste("Accuracy=", round(acc, 2)))
[1] "Accuracy= 0.87"
print(paste("Precision=", round(prec, 2)))
[1] "Precision= 0.83"
print(paste("Recall=", round(recall, 2)))
[1] "Recall= 0.86"
print(paste("Specificity=", round(spec, 2)))
[1] "Specificity= 0.88"
print(paste("NPV=", round(npv, 2)))
[1] "NPV= 0.9"
print(paste("F1=", round(f1, 2)))
[1] "F1= 0.85"
print(paste("AUC=", round(auc, 2)))
[1] "AUC= 0.9"
# Importance
bst <- xgboost( params = param,
data = as.matrix(selectedDf %>% select(-c(Class, clsPred))) ,
label = selectedDf$Class,
nrounds = 100,
verbose = F,
prediction = T,
maximize = F, # Change this value to F will help to run with more itineration
nfold = n_folds,
metrics = c("auc", "error"),
early_stopping_rounds = 50,
stratified = T,
scale_pos_weight = 1)
importanceDf <- xgb.importance(colnames(selectedDf %>% select(-c(Class, clsPred))), model = bst)
print(importanceDf)
library(pROC)
dfROC <- pROC::roc(response = ifelse(selectedDf$Class==T, 1, 0),
predictor = round(xgb_m$pred),
levels=c(0, 1), direction = "<")
# it = which.max(xgb_m$evaluation_log$test_auc_mean)
# best.iter = xgb_m$evaluation_log$iter[it]
# best.iter
plot(pROC::roc(response = ifelse(selectedDf$Class==T, 1, 0),
predictor = round(xgb_m$pred),
levels=c(0, 1), direction = "<"),
legacy.axes = TRUE,
main="ROC Curve",
lwd=1.5)

Plot feature importance
yAxis <- list(
title = 'Importance',
range=c(0.0, 1.0)
)
xAxis <- list(
title = ''
)
importanceDf$Feature <- factor(importanceDf$Feature, levels = importanceDf[order(-Gain),]$Feature)
fig_Importance <- plot_ly(importanceDf, x = ~Feature, y = ~Gain, type = 'bar', name = 'Gain', width=600) %>%
add_trace(y = ~Cover, name = 'Cover') %>%
add_trace(y = ~Frequency, name = 'Frequency') %>%
layout(yaxis = yAxis, xaxis=xAxis, barmode = 'group', title="Feature Importance") %>%
config(.Last.value, mathjax = 'cdn')
htmltools::tagList(fig_Importance)
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CnNvdXJjZSgnLi4vc2V0dGluZ3Mvc2V0dGluZ3MuUicpCnNvdXJjZSgnY29tbW9uRnVuY3Rpb25zLlInKQpsaWJyYXJ5KG5sbWUpCmBgYAoKYGBge3J9CnNldC5zZWVkKDQzKQpkcml2ZTEgPC0gcmVhZC5jc3YoJy4uL2RhdGEvcHJvY2Vzc2VkL2FuYWx5c2lzL1RUMV9Ecml2ZV8xX1BQLmNzdicpCmRyaXZlMiA8LSByZWFkLmNzdignLi4vZGF0YS9wcm9jZXNzZWQvQW5hbHlzaXMvVFQxX0RyaXZlXzJfUFAuY3N2JykKZHJpdmUzIDwtIHJlYWQuY3N2KCcuLi9kYXRhL3Byb2Nlc3NlZC9BbmFseXNpcy9UVDFfRHJpdmVfM19QUC5jc3YnKQpkcml2ZTQgPC0gcmVhZC5jc3YoJy4uL2RhdGEvcHJvY2Vzc2VkL0FuYWx5c2lzL1RUMV9Ecml2ZV80X1BQLmNzdicsIHN0cmluZ3NBc0ZhY3RvcnMgPSBUKQpgYGAKCmBgYHtyfQpkZlNlZyA8LSBkYXRhLmZyYW1lKHJlcCgxLCBucm93KGRyaXZlNCkpLCByZXAoMiwgbnJvdyhkcml2ZTQpKSwgcmVwKDMsIG5yb3coZHJpdmU0KSksIHJlcCg0LCBucm93KGRyaXZlNCkpKQpuYW1lcyhkZlNlZykgPC0gYygiU2VnMSIsICJTZWcyIiwgIlNlZzMiLCAiU2VnNCIpCgpjb21iaW5lZERmX1NlZzEgPC0gY2JpbmQoZHJpdmU0LCAKICAgICAgICAgICAgICAgICAgICBkcml2ZTEkTWVhblBQX1NlZzAsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRNZWFuUFBfU2VnMSwgZHJpdmUzJE1lYW5QUF9TZWcxLCAKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkTWVhblBQX1NlZzBfMSwgZHJpdmUzJE1lYW5QUF9TZWcwXzEsCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJFN0ZFBQX1NlZzEsIGRyaXZlMyRTdGRQUF9TZWcxLAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRTdGRQUF9TZWcwXzEsIGRyaXZlMyRTdGRQUF9TZWcwXzEsCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJE1lYW5QUF9BY2NIaWdoMSwgZHJpdmUzJE1lYW5QUF9BY2NIaWdoMSwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkWC5NZWFuUFBfQWNjTG93MSwgZHJpdmUzJFguTWVhblBQX0FjY0xvdzEsCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJFN0ZFBQX0FjY0hpZ2gxLCBkcml2ZTMkU3RkUFBfQWNjSGlnaDEsCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJFN0ZFBQX0FjY0xvdzEsIGRyaXZlMyRTdGRQUF9BY2NMb3cxLAogICAgICAgICAgICAgICAgICAgIGRmU2VnJFNlZzEKICAgICAgICAgICAgICAgICAgKQpjb21iaW5lZERmX1NlZzIgPC0gY2JpbmQoZHJpdmU0LCAKICAgICAgICAgICAgICAgICAgICBkcml2ZTEkTWVhblBQX1NlZzAsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRNZWFuUFBfU2VnMiwgZHJpdmUzJE1lYW5QUF9TZWcyLCAKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkTWVhblBQX1NlZzBfMiwgZHJpdmUzJE1lYW5QUF9TZWcwXzIsCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJFN0ZFBQX1NlZzIsIGRyaXZlMyRTdGRQUF9TZWcyLAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRTdGRQUF9TZWcwXzIsIGRyaXZlMyRTdGRQUF9TZWcwXzIsCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJE1lYW5QUF9BY2NIaWdoMiwgZHJpdmUzJE1lYW5QUF9BY2NIaWdoMiwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkWC5NZWFuUFBfQWNjTG93MiwgZHJpdmUzJFguTWVhblBQX0FjY0xvdzIsCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJFN0ZFBQX0FjY0hpZ2gyLCBkcml2ZTMkU3RkUFBfQWNjSGlnaDIsCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJFN0ZFBQX0FjY0xvdzIsIGRyaXZlMyRTdGRQUF9BY2NMb3cyLAogICAgICAgICAgICAgICAgICAgIGRmU2VnJFNlZzIKICAgICAgICAgICAgICAgICAgKQpjb21iaW5lZERmX1NlZzMgPC0gY2JpbmQoZHJpdmU0LCAKICAgICAgICAgICAgICAgICAgICBkcml2ZTEkTWVhblBQX1NlZzAsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRNZWFuUFBfU2VnMywgZHJpdmUzJE1lYW5QUF9TZWczLCAKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkTWVhblBQX1NlZzBfMywgZHJpdmUzJE1lYW5QUF9TZWcwXzMsCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJFN0ZFBQX1NlZzMsIGRyaXZlMyRTdGRQUF9TZWczLAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRTdGRQUF9TZWcwXzMsIGRyaXZlMyRTdGRQUF9TZWcwXzMsCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJE1lYW5QUF9BY2NIaWdoMywgZHJpdmUzJE1lYW5QUF9BY2NIaWdoMywKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkWC5NZWFuUFBfQWNjTG93MywgZHJpdmUzJFguTWVhblBQX0FjY0xvdzMsCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJFN0ZFBQX0FjY0hpZ2gzLCBkcml2ZTMkU3RkUFBfQWNjSGlnaDMsCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJFN0ZFBQX0FjY0xvdzMsIGRyaXZlMyRTdGRQUF9BY2NMb3czLAogICAgICAgICAgICAgICAgICAgIGRmU2VnJFNlZzMKICAgICAgICAgICAgICAgICAgKQpjb21iaW5lZERmX1NlZzQgPC0gY2JpbmQoZHJpdmU0LCAKICAgICAgICAgICAgICAgICAgICBkcml2ZTEkTWVhblBQX1NlZzAsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRNZWFuUFBfU2VnNCwgZHJpdmUzJE1lYW5QUF9TZWc0LCAKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkTWVhblBQX1NlZzBfNCwgZHJpdmUzJE1lYW5QUF9TZWcwXzQsCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJFN0ZFBQX1NlZzQsIGRyaXZlMyRTdGRQUF9TZWc0LAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRTdGRQUF9TZWcwXzQsIGRyaXZlMyRTdGRQUF9TZWcwXzQsCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJE1lYW5QUF9BY2NIaWdoNCwgZHJpdmUzJE1lYW5QUF9BY2NIaWdoNCwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkWC5NZWFuUFBfQWNjTG93NCwgZHJpdmUzJFguTWVhblBQX0FjY0xvdzQsCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJFN0ZFBQX0FjY0hpZ2g0LCBkcml2ZTMkU3RkUFBfQWNjSGlnaDQsCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJFN0ZFBQX0FjY0xvdzQsIGRyaXZlMyRTdGRQUF9BY2NMb3c0LAogICAgICAgICAgICAgICAgICAgIGRmU2VnJFNlZzQKICAgICAgICAgICAgICAgICAgKQoKY29tbW9uX25hbWVzIDwtIGMoIlBQX0Rldl8xX1R1cm5pbmciLAogICAgICAgICAgICAgICAgICAiUFBfRGV2XzJfU3RyYWlnaHQiLCAiUFBfRGV2XzNfU3RyYWlnaHQiLCAKICAgICAgICAgICAgICAgICAgIlBQX0Rldl8yX1R1cm5pbmciLCAiUFBfRGV2XzNfVHVybmluZyIsIAogICAgICAgICAgICAgICAgICAiU3RkX1BQXzJfU3RyYWlnaHQiLCAiU3RkX1BQXzNfU3RyYWlnaHQiLCAKICAgICAgICAgICAgICAgICAgIlN0ZF9QUF8yX1R1cm5pbmciLCAiU3RkX1BQXzNfVHVybmluZyIsCiAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAiTWVhbl9QUF8yX0FjY0hpZ2giLCAiTWVhbl9QUF8zX0FjY0hpZ2giLAogICAgICAgICAgICAgICAgICAiTWVhbl9QUF8yX0FjY0xvdyIsICJNZWFuX1BQXzNfQWNjTG93IiwKICAgICAgICAgICAgICAgICAgIlN0ZF9QUF8yX0FjY0hpZ2giLCAiU3RkX1BQXzNfQWNjSGlnaCIsCiAgICAgICAgICAgICAgICAgICJTdGRfUFBfMl9BY2NMb3ciLCAiU3RkX1BQXzNfQWNjTG93IiwKICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICJTZWdtZW50IikKCm5hbWVzKGNvbWJpbmVkRGZfU2VnMSkgPC0gYyhuYW1lcyhkcml2ZTQpLCBjb21tb25fbmFtZXMpCm5hbWVzKGNvbWJpbmVkRGZfU2VnMikgPC0gYyhuYW1lcyhkcml2ZTQpLCBjb21tb25fbmFtZXMpCm5hbWVzKGNvbWJpbmVkRGZfU2VnMykgPC0gYyhuYW1lcyhkcml2ZTQpLCBjb21tb25fbmFtZXMpCm5hbWVzKGNvbWJpbmVkRGZfU2VnNCkgPC0gYyhuYW1lcyhkcml2ZTQpLCBjb21tb25fbmFtZXMpCgojIGNvbWJpbmVkRGZfU2VnMSRTdWJqZWN0IDwtIHBhc3RlMChhcy5mYWN0b3IoY29tYmluZWREZl9TZWcxJFN1YmplY3QpLCAiLlMxIikKIyBjb21iaW5lZERmX1NlZzIkU3ViamVjdCA8LSBwYXN0ZTAoYXMuZmFjdG9yKGNvbWJpbmVkRGZfU2VnMiRTdWJqZWN0KSwgIi5TMiIpCiMgY29tYmluZWREZl9TZWczJFN1YmplY3QgPC0gcGFzdGUwKGFzLmZhY3Rvcihjb21iaW5lZERmX1NlZzMkU3ViamVjdCksICIuUzMiKQojIGNvbWJpbmVkRGZfU2VnNCRTdWJqZWN0IDwtIHBhc3RlMChhcy5mYWN0b3IoY29tYmluZWREZl9TZWc0JFN1YmplY3QpLCAiLlM0IikKCmNvbWJpbmVkRGYgPC0gcmJpbmQoY29tYmluZWREZl9TZWcxLCBjb21iaW5lZERmX1NlZzIsIGNvbWJpbmVkRGZfU2VnMywgY29tYmluZWREZl9TZWc0KQoKIyBjb21iaW5lZERmJFN1YmplY3QgPC0gcGFzdGUwKCIjIiwgc3RyX3BhZChjb21iaW5lZERmJFN1YmplY3QsIDIsIHBhZD0iMCIpKQpjb21iaW5lZERmJFNlZ21lbnQgPC0gYXMuZmFjdG9yKGNvbWJpbmVkRGYkU2VnbWVudCkKY29tYmluZWREZiRBY3Rpdml0eUVuY29kZWQgPC0gZmFjdG9yKGlmZWxzZShjb21iaW5lZERmJEFjdGl2aXR5ID09ICJOTyIsICIxIiwgaWZlbHNlKGNvbWJpbmVkRGYkQWN0aXZpdHkgPT0gIkMiLCAiMiIsICIzIikpKQoKY29tYmluZWREZiA8LSBjb21iaW5lZERmW2NvbXBsZXRlLmNhc2VzKGNvbWJpbmVkRGYpLF0KY29tYmluZWREZiRTdWJqZWN0ID0gYXMuZmFjdG9yKGNvbWJpbmVkRGYkU3ViamVjdCkKYGBgCgoKYGBge3J9Cm1vZGVsID0gbG0oUFBfQWZ0ZXIgfiAKICAgICAgICAgICAgICBQUF9EZXZfMl9TdHJhaWdodCArIAogICAgICAgICAgICAgIFBQX0Rldl8zX1N0cmFpZ2h0ICsKICAgICAgICAgICAgICBQUF9EZXZfMl9UdXJuaW5nICsgCiAgICAgICAgICAgICAgUFBfRGV2XzNfVHVybmluZyArIAogICAgICAgICAgICAgIFN0ZF9QUF8yX1N0cmFpZ2h0ICsgCiAgICAgICAgICAgICAgU3RkX1BQXzNfU3RyYWlnaHQgKyAKICAgICAgICAgICAgICBTdGRfUFBfMl9UdXJuaW5nICsKICAgICAgICAgICAgICBTdGRfUFBfM19UdXJuaW5nICsKICAgICAgICAgICAgICAjIFBQX1ByaW9yICsKICAgICAgICAgICAgICBmYWN0b3IoQWN0aXZpdHlFbmNvZGVkKSwKICAgICAgICAgICAgZGF0YT1jb21iaW5lZERmLCByYW5kb20gPSB+MXxmYWN0b3IoU3ViamVjdCksIG1ldGhvZCA9ICJSRU1MIikKCiMgYW5vdmEobW9kZWwpCnN1bW1hcnkobW9kZWwpCnBsb3QobW9kZWwpCmBgYAoKIyBObyBSYW5kb20gRWZmZWN0cwpgYGB7cn0KbGluZWFyTW9kZWwxIDwtIGxtKFBQX0FmdGVyIH4gCiAgICAgICAgICAgICAgICBNZWFuX1BQXzJfQWNjSGlnaAogICAgICAgICAgICAgICsgTWVhbl9QUF8yX0FjY0xvdwogICAgICAgICAgICAgICsgTWVhbl9QUF8zX0FjY0hpZ2gKICAgICAgICAgICAgICArIE1lYW5fUFBfM19BY2NMb3cKICAgICAgICAgICAgICArIFN0ZF9QUF8yX0FjY0hpZ2gKICAgICAgICAgICAgICArIFN0ZF9QUF8yX0FjY0xvdwogICAgICAgICAgICAgICsgU3RkX1BQXzNfQWNjSGlnaAogICAgICAgICAgICAgICsgU3RkX1BQXzNfQWNjTG93CiAgICAgICAgICAgICAgIyArIFBQX1ByaW9yCiAgICAgICAgICAgICAgKyBmYWN0b3IoQWN0aXZpdHlFbmNvZGVkKSwKICAgICAgICAgICAgZGF0YT1jb21iaW5lZERmKQoKIyBhbm92YShtb2RlbCkKc3VtbWFyeShsaW5lYXJNb2RlbDEpCnBsb3QobGluZWFyTW9kZWwxKQpgYGAKCgojIFdpdGggUmFuZG9tIEVmZmVjdHMKYGBge3J9CmxpbmVhck1vZGVsMSA8LSBsbWUoUFBfQWZ0ZXIgfiAKICAgICAgICAgICAgICAgIE1lYW5fUFBfMl9BY2NIaWdoCiAgICAgICAgICAgICAgKyBNZWFuX1BQXzJfQWNjTG93CiAgICAgICAgICAgICAgKyBNZWFuX1BQXzNfQWNjSGlnaAogICAgICAgICAgICAgICsgTWVhbl9QUF8zX0FjY0xvdwogICAgICAgICAgICAgICsgU3RkX1BQXzJfQWNjSGlnaAogICAgICAgICAgICAgICsgU3RkX1BQXzJfQWNjTG93CiAgICAgICAgICAgICAgKyBTdGRfUFBfM19BY2NIaWdoCiAgICAgICAgICAgICAgKyBTdGRfUFBfM19BY2NMb3cKICAgICAgICAgICAgICAjICsgUFBfUHJpb3IKICAgICAgICAgICAgICArIGZhY3RvcihBY3Rpdml0eUVuY29kZWQpLAogICAgICAgICAgICBkYXRhPWNvbWJpbmVkRGYsIHJhbmRvbSA9IH4xfGZhY3RvcihTdWJqZWN0KSwgbWV0aG9kID0gIlJFTUwiKQoKIyBhbm92YShtb2RlbCkKc3VtbWFyeShsaW5lYXJNb2RlbDEpCnBsb3QobGluZWFyTW9kZWwxKQpgYGAKCiMjIE1hY2hpbmUgTGVhcm5pbmcKCmBgYHtyfQpwcEFmdGVyIDwtIGNvbWJpbmVkRGYkUFBfQWZ0ZXIKcHBBZnRlckFycmF5IDwtIG1hdHJpeChwcEFmdGVyLCBucm93ID0gMSxuY29sID0gbGVuZ3RoKHBwQWZ0ZXIpKQogIAp0aHJlc2hvbGRQUEFmdGVyIDwtIG90c3UocHBBZnRlckFycmF5LCByYW5nZT1jKG1pbihwcEFmdGVyKSwgbWF4KHBwQWZ0ZXIpKSkgIyBFeHBlY3RlZCBUaHJlc2hvbGQgPiAwLjEwMTIzCnByaW50KHBhc3RlMCgnVGhyZXNob2xkOiAnLCB0aHJlc2hvbGRQUEFmdGVyKSkKCnNlbGVjdGVkRGYgPC0gY29tYmluZWREZiAlPiUgc2VsZWN0KAogICAgICAgICAgICAgICAgICAiU3ViamVjdCIsICJBY3Rpdml0eSIsICJQUF9BZnRlciIsICJQUF9QcmlvciIsCiAgICAgICAgICAgICAgICAgICJNZWFuX1BQXzJfQWNjSGlnaCIsICJNZWFuX1BQXzNfQWNjSGlnaCIsCiAgICAgICAgICAgICAgICAgICJNZWFuX1BQXzJfQWNjTG93IiwgIk1lYW5fUFBfM19BY2NMb3ciLAogICAgICAgICAgICAgICAgICAiU3RkX1BQXzJfQWNjSGlnaCIsICJTdGRfUFBfM19BY2NIaWdoIiwKICAgICAgICAgICAgICAgICAgIlN0ZF9QUF8yX0FjY0xvdyIsICJTdGRfUFBfM19BY2NMb3ciKQoKc2VsZWN0ZWREZiRTdWJqZWN0IDwtIE5VTEwKc2VsZWN0ZWREZiRBY3Rpdml0eV9OTyA8LSBpZmVsc2Uoc2VsZWN0ZWREZiRBY3Rpdml0eSA9PSAiTk8iLCAxLCAwKQpzZWxlY3RlZERmJEFjdGl2aXR5X0MgPC0gaWZlbHNlKHNlbGVjdGVkRGYkQWN0aXZpdHkgPT0gIkMiLCAxLCAwKQpzZWxlY3RlZERmJEFjdGl2aXR5X00gPC0gaWZlbHNlKHNlbGVjdGVkRGYkQWN0aXZpdHkgPT0gIk0iLCAxLCAwKQpzZWxlY3RlZERmJEFjdGl2aXR5IDwtIE5VTEwKCiMgc2VsZWN0ZWREZiRQUF9EZXZfMV9UdXJuaW5nIDwtIE5VTEwKIyBzZWxlY3RlZERmJFN0ZF9QUF8yX1N0cmFpZ2h0IDwtIE5VTEwKIyBzZWxlY3RlZERmJFN0ZF9QUF8yX1R1cm5pbmcgPC0gTlVMTAojIHNlbGVjdGVkRGYkU3RkX1BQXzNfU3RyYWlnaHQgPC0gTlVMTAojIHNlbGVjdGVkRGYkU3RkX1BQXzNfVHVybmluZyA8LSBOVUxMCiMgCiMgIyBBY2NvcmRpbmcgdG8gTGluZWFyIG1vZGVsCiMgc2VsZWN0ZWREZiRQUF9EZXZfMl9TdHJhaWdodCA8LSBhYnMoc2VsZWN0ZWREZiRQUF9EZXZfMl9TdHJhaWdodCkKIyBzZWxlY3RlZERmJFBQX0Rldl8zX1N0cmFpZ2h0IDwtIGFicyhzZWxlY3RlZERmJFBQX0Rldl8zX1N0cmFpZ2h0KQojIHNlbGVjdGVkRGYkUFBfRGV2XzJfVHVybmluZyA8LSBhYnMoc2VsZWN0ZWREZiRQUF9EZXZfMl9UdXJuaW5nKQojIHNlbGVjdGVkRGYkUFBfRGV2XzNfVHVybmluZyA8LSBhYnMoc2VsZWN0ZWREZiRQUF9EZXZfM19UdXJuaW5nKQojIHNlbGVjdGVkRGYkUFBfUHJpb3IgPC0gYWJzKHNlbGVjdGVkRGYkUFBfUHJpb3IpICMgTlVMTAoKc2VsZWN0ZWREZiRDbGFzcyA8LSBpZmVsc2Uoc2VsZWN0ZWREZiRQUF9BZnRlciA+PSB0aHJlc2hvbGRQUEFmdGVyLCBULCBGKQpzZWxlY3RlZERmJFBQX0FmdGVyIDwtIE5VTEwKCnByaW50KG5hbWVzKHNlbGVjdGVkRGYpKQpgYGAKCmBgYHtyfQojIGxpYnJhcnkobWVmYSkKIyBjb21iaW5lZERmIDwtIHJlcChjb21iaW5lZERmLCAxMCkgCmBgYAoKYGBge3J9CnNldC5zZWVkKDM5KQpuX2ZvbGRzIDwtIDUKcGFyYW1zIDwtIHBhcmFtIDwtIGxpc3Qob2JqZWN0aXZlICAgICAgID0gImJpbmFyeTpsb2dpc3RpYyIsIAogICAgICAgICAgICAgICBib29zdGVyICAgICAgICAgID0gImdidHJlZSIsCiAgICAgICAgICAgICAgIGV2YWxfbWV0cmljICAgICAgPSAiYXVjIiwKICAgICAgICAgICAgICAgZXRhICAgICAgICAgICAgICA9IDAuMSwKICAgICAgICAgICAgICAgbWF4X2RlcHRoICAgICAgICA9IDEwLAogICAgICAgICAgICAgICBhbHBoYSAgICAgICAgICAgID0gMSwKICAgICAgICAgICAgICAgbGFtYmRhICAgICAgICAgICA9IDAsCiAgICAgICAgICAgICAgIGdhbW1hICAgICAgICAgICAgPSAwLjQ1LAogICAgICAgICAgICAgICBtaW5fY2hpbGRfd2VpZ2h0ID0gMC4zLAogICAgICAgICAgICAgICBzdWJzYW1wbGUgICAgICAgID0gMC41LAogICAgICAgICAgICAgICBjb2xzYW1wbGVfYnl0cmVlID0gMSkKICAgICAgICAgICAKIyBYR0Jvb3N0IE1vZGVsICAgICAgICAgCnhnYl9tIDwtIHhnYi5jdiggICBwYXJhbXMgICAgICAgICAgICAgICA9IHBhcmFtLAogICAgICAgICAgICAgICAgICBkYXRhID0gYXMubWF0cml4KHNlbGVjdGVkRGYgJT4lIHNlbGVjdCgtQ2xhc3MpKSAsCiAgICAgICAgICAgICAgICAgIGxhYmVsID0gIHNlbGVjdGVkRGYkQ2xhc3MsCiAgICAgICAgICAgICAgICAgIG5yb3VuZHMgICAgICAgICAgICAgPSAxMDAsCiAgICAgICAgICAgICAgICAgIHZlcmJvc2UgICAgICAgICAgICAgPSBGLAogICAgICAgICAgICAgICAgICBwcmVkaWN0aW9uICAgICAgICAgID0gVCwKICAgICAgICAgICAgICAgICAgbWF4aW1pemUgICAgICAgICAgICA9IEYsICMgQ2hhbmdlIHRoaXMgdmFsdWUgdG8gRiB3aWxsIGhlbHAgdG8gcnVuIHdpdGggbW9yZSBpdGluZXJhdGlvbgogICAgICAgICAgICAgICAgICBuZm9sZCAgICAgICAgICAgICAgID0gbl9mb2xkcywKICAgICAgICAgICAgICAgICAgbWV0cmljcyAgICAgICAgICAgICA9IGMoImF1YyIsICJlcnJvciIpLAogICAgICAgICAgICAgICAgICBlYXJseV9zdG9wcGluZ19yb3VuZHMgPSA1MCwKICAgICAgICAgICAgICAgICAgc3RyYXRpZmllZCAgICAgICAgICAgID0gVCwKICAgICAgICAgICAgICAgICAgc2NhbGVfcG9zX3dlaWdodCAgICAgID0gMikKCiMgeGdiX20kZXZhbHVhdGlvbl9sb2dbeGdiX20kYmVzdF9pdGVyYXRpb24sInRlc3RfYXVjX21lYW4iXQp4Z2JfbSRldmFsdWF0aW9uX2xvZ1t4Z2JfbSRiZXN0X2l0ZXJhdGlvbixdCgpgYGAKCiMjIFBlcmZvcm1hbmNlIE1ldHJpY3MKYGBge3J9CiMgUHJlZGljdGlvbgpzZWxlY3RlZERmJGNsc1ByZWQgPC0gcm91bmQoeGdiX20kcHJlZCkKCmNvbXB1dGVQZXJmb3JtYW5jZVJlc3VsdHMgPC0gZnVuY3Rpb24oc2RhdCl7CiAgc2RhdCA9IHNkYXRbY29tcGxldGUuY2FzZXMoc2RhdCksXQogIGFjYyA9IHN1bShzZGF0WywxXSA9PSBzZGF0WywyXSkvbnJvdyhzZGF0KQogIGNvbmZfbWF0ID0gdGFibGUoc2RhdCkKICBzcGVjaWYgPSBjb25mX21hdFsxLDFdL3N1bShjb25mX21hdFssMV0pCiAgc2Vuc2l2ID0gY29uZl9tYXRbMiwyXS9zdW0oY29uZl9tYXRbLDJdKQogIHByZWNpID0gIGNvbmZfbWF0WzIsMl0vc3VtKGNvbmZfbWF0WzIsXSkKICBucHYgPSAgICBjb25mX21hdFsxLDFdL3N1bShjb25mX21hdFsxLF0pCiAgcmV0dXJuKGMoYWNjLHNwZWNpZixzZW5zaXYscHJlY2ksbnB2KSkKfQoKIyBHZXQgYXZlcmFnZSBwZXJmb3JtYW5jZQpwZXJmb3JtYW5jZSA8LSBjb21wdXRlUGVyZm9ybWFuY2VSZXN1bHRzKHNlbGVjdGVkRGYgJT4lIHNlbGVjdChDbGFzcywgY2xzUHJlZCkpCmFjYyA8LSBwZXJmb3JtYW5jZVsxXQpwcmVjIDwtIHBlcmZvcm1hbmNlWzRdCnJlY2FsbCA8LSBwZXJmb3JtYW5jZVszXQpzcGVjIDwtIHBlcmZvcm1hbmNlWzJdCm5wdiA8LSBwZXJmb3JtYW5jZVs1XQpmMSA8LSAoMiAqIHJlY2FsbCAqIHByZWMpIC8gKHJlY2FsbCArIHByZWMpCmF1YyA8LSBhcy5udW1lcmljKHhnYl9tJGV2YWx1YXRpb25fbG9nW3hnYl9tJGJlc3RfaXRlcmF0aW9uLCAidGVzdF9hdWNfbWVhbiJdKQoKcHJpbnQocGFzdGUoIkFjY3VyYWN5PSIsIHJvdW5kKGFjYywgMikpKQpwcmludChwYXN0ZSgiUHJlY2lzaW9uPSIsIHJvdW5kKHByZWMsIDIpKSkKcHJpbnQocGFzdGUoIlJlY2FsbD0iLCByb3VuZChyZWNhbGwsIDIpKSkKcHJpbnQocGFzdGUoIlNwZWNpZmljaXR5PSIsIHJvdW5kKHNwZWMsIDIpKSkKcHJpbnQocGFzdGUoIk5QVj0iLCByb3VuZChucHYsIDIpKSkKcHJpbnQocGFzdGUoIkYxPSIsIHJvdW5kKGYxLCAyKSkpCnByaW50KHBhc3RlKCJBVUM9Iiwgcm91bmQoYXVjLCAyKSkpCmBgYAoKYGBge3J9CiMgSW1wb3J0YW5jZQpic3QgPC0geGdib29zdCggICBwYXJhbXMgICAgICAgICAgICAgICA9IHBhcmFtLAogICAgICAgICAgICAgICAgICBkYXRhID0gYXMubWF0cml4KHNlbGVjdGVkRGYgJT4lIHNlbGVjdCgtYyhDbGFzcywgY2xzUHJlZCkpKSAsCiAgICAgICAgICAgICAgICAgIGxhYmVsID0gIHNlbGVjdGVkRGYkQ2xhc3MsCiAgICAgICAgICAgICAgICAgIG5yb3VuZHMgICAgICAgICAgICAgPSAxMDAsCiAgICAgICAgICAgICAgICAgIHZlcmJvc2UgICAgICAgICAgICAgPSBGLAogICAgICAgICAgICAgICAgICBwcmVkaWN0aW9uICAgICAgICAgID0gVCwKICAgICAgICAgICAgICAgICAgbWF4aW1pemUgICAgICAgICAgICA9IEYsICMgQ2hhbmdlIHRoaXMgdmFsdWUgdG8gRiB3aWxsIGhlbHAgdG8gcnVuIHdpdGggbW9yZSBpdGluZXJhdGlvbgogICAgICAgICAgICAgICAgICBuZm9sZCAgICAgICAgICAgICAgID0gbl9mb2xkcywKICAgICAgICAgICAgICAgICAgbWV0cmljcyAgICAgICAgICAgICA9IGMoImF1YyIsICJlcnJvciIpLAogICAgICAgICAgICAgICAgICBlYXJseV9zdG9wcGluZ19yb3VuZHMgPSA1MCwKICAgICAgICAgICAgICAgICAgc3RyYXRpZmllZCAgICAgICAgICAgID0gVCwKICAgICAgICAgICAgICAgICAgc2NhbGVfcG9zX3dlaWdodCAgICAgID0gMSkKaW1wb3J0YW5jZURmIDwtIHhnYi5pbXBvcnRhbmNlKGNvbG5hbWVzKHNlbGVjdGVkRGYgJT4lIHNlbGVjdCgtYyhDbGFzcywgY2xzUHJlZCkpKSwgbW9kZWwgPSBic3QpCnByaW50KGltcG9ydGFuY2VEZikKYGBgCgpgYGB7cn0KbGlicmFyeShwUk9DKQoKZGZST0MgPC0gcFJPQzo6cm9jKHJlc3BvbnNlID0gaWZlbHNlKHNlbGVjdGVkRGYkQ2xhc3M9PVQsIDEsIDApLAogICAgICAgICAgICAgICBwcmVkaWN0b3IgPSByb3VuZCh4Z2JfbSRwcmVkKSwKICAgICAgICAgICAgICAgbGV2ZWxzPWMoMCwgMSksIGRpcmVjdGlvbiA9ICI8IikKCiMgaXQgPSB3aGljaC5tYXgoeGdiX20kZXZhbHVhdGlvbl9sb2ckdGVzdF9hdWNfbWVhbikKIyBiZXN0Lml0ZXIgPSB4Z2JfbSRldmFsdWF0aW9uX2xvZyRpdGVyW2l0XQojIGJlc3QuaXRlciAKCnBsb3QocFJPQzo6cm9jKHJlc3BvbnNlID0gaWZlbHNlKHNlbGVjdGVkRGYkQ2xhc3M9PVQsIDEsIDApLAogICAgICAgICAgICAgICBwcmVkaWN0b3IgPSByb3VuZCh4Z2JfbSRwcmVkKSwKICAgICAgICAgICAgICAgbGV2ZWxzPWMoMCwgMSksIGRpcmVjdGlvbiA9ICI8IiksIAogICAgIGxlZ2FjeS5heGVzID0gVFJVRSwKICAgICBtYWluPSJST0MgQ3VydmUiLCAKICAgICBsd2Q9MS41KSAKYGBgCgoKIyMjIFBsb3QgZmVhdHVyZSBpbXBvcnRhbmNlCmBgYHtyfQp5QXhpcyA8LSBsaXN0KAogIHRpdGxlID0gJ0ltcG9ydGFuY2UnLAogIHJhbmdlPWMoMC4wLCAxLjApCikKeEF4aXMgPC0gbGlzdCgKICB0aXRsZSA9ICcnCikKCmltcG9ydGFuY2VEZiRGZWF0dXJlIDwtIGZhY3RvcihpbXBvcnRhbmNlRGYkRmVhdHVyZSwgbGV2ZWxzID0gaW1wb3J0YW5jZURmW29yZGVyKC1HYWluKSxdJEZlYXR1cmUpCmZpZ19JbXBvcnRhbmNlIDwtIHBsb3RfbHkoaW1wb3J0YW5jZURmLCB4ID0gfkZlYXR1cmUsIHkgPSB+R2FpbiwgdHlwZSA9ICdiYXInLCBuYW1lID0gJ0dhaW4nLCB3aWR0aD02MDApICU+JQogIGFkZF90cmFjZSh5ID0gfkNvdmVyLCBuYW1lID0gJ0NvdmVyJykgJT4lIAogIGFkZF90cmFjZSh5ID0gfkZyZXF1ZW5jeSwgbmFtZSA9ICdGcmVxdWVuY3knKSAlPiUgCiAgbGF5b3V0KHlheGlzID0geUF4aXMsIHhheGlzPXhBeGlzLCBiYXJtb2RlID0gJ2dyb3VwJywgdGl0bGU9IkZlYXR1cmUgSW1wb3J0YW5jZSIpICU+JSAKICBjb25maWcoLkxhc3QudmFsdWUsIG1hdGhqYXggPSAnY2RuJykKCmh0bWx0b29sczo6dGFnTGlzdChmaWdfSW1wb3J0YW5jZSkKYGBgCgoK